package cn.wp.common.core.util;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.wp.common.core.exception.WpException;
import cn.wp.common.core.model.WpTree;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 树工具类
 * Created by chenyb on 2019/12/25
 */
public class TreeUtil {

    public static <T> List<WpTree> build(List<T> list,String rootValue,String parentFieldName,Mapping mapping,Builder<T> builder){
        List<WpTree> tree = Lists.newArrayList();
        try{
            for(T t : list){
                Class<?> clazz = t.getClass();
                String value = getValue(t,parentFieldName);
                if(rootValue.equals(value)){

                    WpTree wpTree = new WpTree();
                    mapping.forEach((key, objectFieldName) -> {
                        wpTree.put(key,getValue(t,(String) objectFieldName));
                    });

                    if(builder != null){
                        builder.build(wpTree,t);
                    }

                    tree.add(wpTree);
                    recursionBuild(list,wpTree,parentFieldName,mapping,builder);

                   /* wpTree.setId(this.getValue(t,mapping.getString(WpTree.TREE_ID)));
                    wpTree.setName(this.getValue(t,mapping.getString(WpTree.TREE_NAME)));
                    wpTree.setCode(this.getValue(t,mapping.getString(WpTree.TREE_CODE)));
                    wpTree.setChild(this.getValue(t,mapping.getString(WpTree.TREE_CHILD)));
                    wpTree.setExtra(this.getValue(t,mapping.getString(WpTree.TREE_EXTRA)));
                    wpTree.setIcon(this.getValue(t,mapping.getString(WpTree.TREE_ICON)));
                    wpTree.setUrl(this.getValue(t,mapping.getString(WpTree.TREE_URL)));
                    wpTree.setLeaf(this.getValue(t,mapping.getString(WpTree.TREE_LEFA)));*/

                }
            }
        }catch (Exception ex){
            throw new WpException("树模型构建出错",ex);
        }
        return tree;
    };

    private static <T> void recursionBuild(List<T> list,WpTree wpTree,String parentFieldName,Mapping mapping,Builder<T> builder){
        try{
            for(T t : list){
                Class<?> clazz = t.getClass();
                // 当前节点ID，即子节点的父节点ID
                String pid = (String)wpTree.get(mapping.getFinalKey(WpTree.TREE_ID));
                // 子节点的父节点ID
                String childPid = getValue(t,mapping.getFinalKey(parentFieldName));

                if(pid.equals(childPid)){
                    List<WpTree> childList = (List<WpTree>)wpTree.get(mapping.getFinalKey(WpTree.TREE_CHILD));
                    if(childList == null){
                        childList = Lists.newArrayList();
                        wpTree.put(mapping.getFinalKey(WpTree.TREE_CHILD),childList);
                    }

                    WpTree child = new WpTree();
                    mapping.forEach((key, objectFieldName) -> {
                        child.put(key,getValue(t,(String) objectFieldName));
                    });

                    if(builder != null){
                        builder.build(child,t);
                    }

                    childList.add(child);
                    recursionBuild(list,child,parentFieldName,mapping,builder);
                }
            }
        }catch (Exception ex){
            throw new WpException("树模型构建出错",ex);
        }
    };

    private static String getValue(Object o,String fieldName){
        if(o == null || fieldName == null) {
            return null;
        }
        return String.valueOf(ReflectUtil.getFieldValue(o,fieldName));
    }

    private static boolean isDefaultAttr(String key){
        if(WpTree.TREE_ID.equals(key)){
            return true;
        }

        if(WpTree.TREE_NAME.equals(key)){
            return true;
        }

        if(WpTree.TREE_ICON.equals(key)){
            return true;
        }

        if(WpTree.TREE_URL.equals(key)){
            return true;
        }

        if(WpTree.TREE_CHILD.equals(key)){
            return true;
        }

        if(WpTree.TREE_CODE.equals(key)){
            return true;
        }

        if(WpTree.TREE_LEFA.equals(key)){
            return true;
        }

        if(WpTree.TREE_EXTRA.equals(key)){
            return true;
        }

        if(WpTree.TREE_PARENT_ID.equals(key)){
            return true;
        }

        return false;
    }

    public static class Mapping extends LinkedHashMap {

        private Map<String,String> keyMapping = Maps.newHashMap();

        public Mapping addMapping(String defaultKey,String valueKey){
            super.put(defaultKey,valueKey);
            return this;
        }

        public Mapping addMapping(String defaultKey,String valueKey,String finalKey){
            keyMapping.put(defaultKey,finalKey);
            super.put(finalKey,valueKey);
            return this;
        }

        public String getString(String key){
            String value = (String)super.get(key);
            return value;
        }

        public String getFinalKey(String defaultKey){
            String key = keyMapping.get(defaultKey);
            if(StrUtil.isBlank(key)){
                return defaultKey;
            }
            return key;
        }

    }

    public static interface Builder<T> {
        public void build(WpTree tree, T o);
    }

    @Data
    @AllArgsConstructor
    public static class D{
        private int userId;
        private String userName;
        private int parentId;
    }

    public static void main(String[] args) {
        D d1 = new D(1,"张三",0);
        D d2 = new D(2,"李四",1);
        D d3 = new D(3,"王五",2);

        List<D> list = Lists.newArrayList();
        list.add(d1);
        list.add(d2);
        list.add(d3);

        Mapping mapping = new Mapping();
        mapping.addMapping(WpTree.TREE_ID,"userId","tid");
        mapping.addMapping(WpTree.TREE_NAME,"userName");
        mapping.addMapping(WpTree.TREE_PARENT_ID,"parentId","ddd");

        List<WpTree> treeList = TreeUtil.build(list, "0", "parentId", mapping, new Builder<D>() {
            @Override
            public void build(WpTree tree, D o) {
                tree.setIcon("测试自定义构建");
            }
        });
        System.err.println(JSON.toJSONString(treeList));
    }
}
